﻿namespace wToggle.Platform
{
    using System.Collections.Generic;
    using System.Threading.Tasks;

    using wToggle.Platform.Data;
    using wToggle.Platform.Interfaces;

    using XPlatUtils;

    public static class CacheLayer
    {
        internal static TEntity LoadEntity<TEntity>(ulong key) where TEntity : class, IEntity
        {
            var cache = ServiceContainer.TryResolve<ICacheProvider>();

            if (cache == null)
            {
                return default(TEntity);
            }

            return cache.LoadEntity<TEntity>(key);
        }

        internal static ICollection<TEntity> LoadEntities<TEntity>() where TEntity : class, IEntity
        {
            var cache = ServiceContainer.TryResolve<ICacheProvider>();

            if (cache == null)
            {
                return null;
            }

            return cache.LoadEntities<TEntity>();
        }

        internal static async Task StoreEntity<TEntity>(TEntity entity, bool withLock = true) where TEntity : class, IEntity
        {
            var cache = ServiceContainer.TryResolve<ICacheProvider>();

            if (cache == null)
            {
                return;
            }

            await cache.StoreEntity(entity, withLock);
        }

        internal static async Task StoreEntities<TEntity>(IEnumerable<TEntity> entity) where TEntity : class, IEntity
        {
            var cache = ServiceContainer.TryResolve<ICacheProvider>();

            if (cache == null)
            {
                return;
            }

            await cache.StoreEntities(entity);
        }

        internal async static Task Purge()
        {
            var cache = ServiceContainer.TryResolve<ICacheProvider>();

            if (cache == null)
            {
                return;
            }

            await cache.Purge();
        }

        internal static bool HasPendingWrites()
        {
            var cache = ServiceContainer.TryResolve<ICacheProvider>();

            if (cache == null)
            {
                return false;
            }

            return cache.HasPendingWrites();
        }

        internal static async Task StoreEntryWrite<TEntity>(TEntity entry, WriteType type, bool withLock = true) where TEntity : class, IEntity
        {
            var cache = ServiceContainer.TryResolve<ICacheProvider>();

            if (cache == null)
            {
                return;
            }

            await cache.StoreEntryWrite(entry, type, withLock);
        }

        public static async Task<bool> FlushWrites()
        {
            var cache = ServiceContainer.TryResolve<ICacheProvider>();

            if (cache == null)
            {
                return true;
            }

            return await cache.FlushWrites();
        }

        internal static async Task RemoveEntity<T>(ulong id, bool withLock = true) where T : class, IEntity
        {
            var cache = ServiceContainer.TryResolve<ICacheProvider>();

            if (cache == null)
            {
                return;
            }

            await cache.RemoveEntity<T>(id, withLock); 
        }

        public static async Task Scrub()
        {
            var cache = ServiceContainer.TryResolve<ICacheProvider>();

            if (cache == null)
            {
                return;
            }

            var cachedUser = cache.LoadEntity<UserData>(0);

            await cache.Purge();
            await cache.StoreEntity(cachedUser, true);
        }

        public static void UpdateTagReferences(string oldTag, string newTag)
        {
            var cache = ServiceContainer.TryResolve<ICacheProvider>();

            if (cache == null)
            {
                return;
            }

            var entries = cache.LoadEntities<TimeEntry>();

            if (entries != null)
            {
                foreach (var timeEntry in entries)
                {
                    if (timeEntry.TagIds.Remove(oldTag) && !string.IsNullOrEmpty(newTag))
                    {
                        timeEntry.TagIds.Add(newTag);
                    }
                }
            }
        }

        public static void UpdateProjectReferences(ulong oldId, ulong newId)
        {
            var cache = ServiceContainer.TryResolve<ICacheProvider>();

            if (cache == null)
            {
                return;
            }

            var entries = cache.LoadEntities<TimeEntry>();

            if (entries != null)
            {
                foreach (var timeEntry in entries)
                {
                    if (timeEntry.ProjectId == oldId)
                    {
                        timeEntry.ProjectId = newId;
                    }
                }
            }
        }

        public static bool HasPendingChanges()
        {
            var cache = ServiceContainer.TryResolve<ICacheProvider>();

            if (cache == null)
            {
                return false;
            }

            return cache.HasPendingWrites();
        }
    }
}
